/* =========================================================
   ЕГЭ НАЛЕГКЕ — АРХИВ 2027

   Один JS для всей структуры:

   1. Архив
      → карточки месяцев

   2. Месяц
      → карточки недель

   3. Неделя
      → Базовый уровень
      → Хард уровень

   4. Базовый / Хард
      → карточки уроков

   Работает вместе с новым CSS Архива.
   ========================================================= */

(function () {
  "use strict";


  /* =======================================================
     ЗАЩИТА ОТ ПОВТОРНОГО ЗАПУСКА
     ======================================================= */

  if (
    window.__ENL_ARCHIVE_2027_V1__
  ) {
    return;
  }


  window.__ENL_ARCHIVE_2027_V1__ =
    true;


  /* =======================================================
     КЛАССЫ СТРАНИЦ
     ======================================================= */

  var BODY_CLASSES = [
    "enl-archive-root",
    "enl-month-archive",
    "enl-week-archive",
    "enl-learning-route",
    "enl-hard-page"
  ];


  /* =======================================================
     ШАБЛОНЫ
     ======================================================= */

  var MONTH_PATTERN =
    /^(январь|февраль|март|апрель|май|июнь|июль|август|сентябрь|октябрь|ноябрь|декабрь)(?:\s+\d{4})?(?:\s*[—–\-:|].*)?$/i;


  var DATE_RANGE_PATTERN =
    /(?:с\s*)?\d{1,2}[./-]\d{1,2}(?:[./-]\d{2,4})?\s*(?:по|—|–|-)\s*\d{1,2}[./-]\d{1,2}(?:[./-]\d{2,4})?/i;


  var WEEK_TITLE_PATTERN =
    /(?:недел[яи]\s*\d+|неделя\s+с\s+.+\s+по\s+.+)/i;


  var BASE_PATTERN =
  /(?:^|[\s—–\-:|])(база|базовый|обязательный план)(?:\s+знаний|\s+уровень|\s+недели)?(?:$|[\s—–\-:|])/i;


var HARD_PATTERN =
  /(?:^|[\s—–\-:|])(хард|hard|допы на 100 баллов)(?:\s+уровень)?(?:$|[\s—–\-:|])/i;


  var STATUS_PATTERN =
    /^(есть задание|необходимо выполнить задание|задание выполнено|урок выполнен|урок пройден|выполнено|пройдено|готово|дата начала.*)$/i;


  var META_PATTERN =
    /(дедлайн|сдать до|срок|доступно с|откроется|дата и время начала|мск|\d{1,2}\s+[а-яё]+\s+в\s+\d{1,2}:\d{2}|\d{1,2}[.]\d{1,2}.*\d{1,2}:\d{2})/i;


  var LESSON_PATTERN =
    /видеоурок|видео-урок|видео урок|разбор|тест|данетк|домашн|пробн|вебинар|созвон|практик|материал|задание|тренировк|прочитайте|изучите|посмотрите|откройте|выдержк|учебник/i;


  /* =======================================================
     СЛУЖЕБНЫЕ ПЕРЕМЕННЫЕ
     ======================================================= */

  var observer = null;

  var applyTimer = null;

  var stopObserverTimer = null;

  var isApplying = false;


  /* =======================================================
     БАЗОВЫЕ ФУНКЦИИ
     ======================================================= */

  function clean(value) {

    return String(
      value || ""
    )
      .replace(
        /\u00A0/g,
        " "
      )
      .replace(
        /\s+/g,
        " "
      )
      .trim();
  }


function escapeHtml(value) {
  var div = document.createElement("div");
  div.textContent = String(value || "");
  return div.innerHTML;
}

  function removeBodyClasses() {

  /*
   * Не удаляем классы, заданные самим GetCourse.
   * Они используются как постоянный признак типа тренинга.
   *
   * Удаляем только автоматические классы,
   * если они были добавлены нашим JS.
   */

  if (
    document.body.dataset.enlAutoRoute === "base"
  ) {

    document.body.classList.remove(
      "enl-learning-route"
    );

  }

  if (
    document.body.dataset.enlAutoRoute === "hard"
  ) {

    document.body.classList.remove(
      "enl-hard-page"
    );

  }

  document.body.dataset.enlAutoRoute = "";
}

  function getPageHeadingElement() {

    var selectors = [
      ".page-header h1",
      ".gc-main-content .page-header h1",
      ".main-page-block h1",
      ".gc-main-content h1",
      "h1"
    ];


    for (
      var i = 0;
      i < selectors.length;
      i += 1
    ) {

      var headings =
        document.querySelectorAll(
          selectors[i]
        );


      for (
        var j = 0;
        j < headings.length;
        j += 1
      ) {

        var text =
          clean(
            headings[j].textContent
          );


        if (text) {

          return headings[j];
        }
      }
    }


    return null;
  }


  function getPageHeading() {

    var heading =
      getPageHeadingElement();


    return heading
      ? clean(
          heading.textContent
        )
      : "";
  }


  function getPageSource() {

    var breadcrumbs =
      Array.prototype.slice.call(
        document.querySelectorAll(
          ".breadcrumb, .breadcrumbs"
        )
      )
        .map(
          function (element) {
            return clean(
              element.textContent
            );
          }
        )
        .join(" ");


    return clean(
      [
        getPageHeading(),
        document.title,
        breadcrumbs
      ].join(" ")
    );
  }


  function getStreamTable() {

    return document.querySelector(
      ".stream-table"
    );
  }


function getTrainingRows(table) {

  if (!table) {
    return [];
  }


  return Array.prototype.slice.call(
    table.querySelectorAll(
      "tbody > tr"
    )
  ).filter(
    function (row) {

      /*
       * До первого оформления GetCourse
       * использует .stream-title.
       *
       * После нашего оформления название
       * уже находится в одном из классов ниже.
       *
       * Поэтому строка продолжает
       * распознаваться и после перерисовки.
       */
      var title =
        row.querySelector(
          ".stream-title," +
          ".enl-archive-month-title," +
          ".enl-month-week-title," +
          ".enl-level-title"
        );


      var link =
        row.querySelector(
          "a[href]"
        );


      return Boolean(
        title &&
        link
      );
    }
  );
}


  function getRowLink(row) {

    if (!row) {
      return null;
    }


    return (
      row.querySelector(
        "td > a[href]"
      ) ||
      row.querySelector(
        "a[href]"
      )
    );
  }


function getRowTitle(row) {

  if (!row) {
    return "";
  }


  /*
   * Сначала родной заголовок GetCourse.
   *
   * Если карточка уже была оформлена,
   * берём наш новый заголовок.
   */
  var title =
    row.querySelector(
      ".stream-title," +
      ".enl-archive-month-title," +
      ".enl-month-week-title," +
      ".enl-level-title"
    );


  return clean(
    title
      ? title.textContent
      : ""
  );
}


  function getOriginalLinkText(link) {

    if (!link) {
      return "";
    }


    if (
      !link.dataset
        .enlOriginalText
    ) {

      link.dataset
        .enlOriginalText =
        String(
          link.innerText ||
          link.textContent ||
          ""
        );
    }


    return link.dataset
      .enlOriginalText;
  }


  function getRowDescriptionText(
    row
  ) {

    if (!row) {
      return "";
    }


    var title =
      row.querySelector(
        ".stream-title"
      );


    if (
      title &&
      title.nextElementSibling
    ) {

      return clean(
        title
          .nextElementSibling
          .textContent
      );
    }


    var link =
      getRowLink(row);


    if (!link) {
      return "";
    }


    var fullText =
      clean(
        getOriginalLinkText(
          link
        )
      );


    var titleText =
      getRowTitle(row);


    if (
      titleText &&
      fullText.indexOf(
        titleText
      ) !== -1
    ) {

      fullText =
        fullText.replace(
          titleText,
          ""
        );
    }


    return clean(
      fullText
    );
  }


  /* =======================================================
     ОЧИСТКА СИСТЕМНЫХ ПОДПИСЕЙ
     ======================================================= */

  function removeLessonCount(text) {

    return clean(
      String(
        text || ""
      )
        .replace(
          /^\d+\s+урок(?:ов|а)?\.?\s*/i,
          ""
        )
        .replace(
          /^нет\s+уроков\.?\s*/i,
          ""
        )
    );
  }


  function removeNoLessons(text) {

    return clean(
      String(
        text || ""
      )
        .replace(
          /нет\s+уроков\.?/gi,
          ""
        )
    );
  }


  /* =======================================================
     РАЗБИРАЕМ ТЕМЫ / ТЕГИ
     ======================================================= */

  function extractQuotedItems(
    text
  ) {

    var result = [];

    var regexp =
      /«([^»]+)»/g;

    var match;


    while (
      (
        match =
          regexp.exec(
            String(
              text || ""
            )
          )
      )
    ) {

      var value =
        clean(
          match[1]
        );


      if (
        value &&
        result.indexOf(
          value
        ) === -1
      ) {

        result.push(
          value
        );
      }
    }


    return result;
  }


  function splitItems(
    text
  ) {

    return String(
      text || ""
    )
      .replace(
        /[«»]/g,
        ""
      )
      .split(
        /\s*\|\s*/
      )
      .map(
        function (item) {

          return clean(
            item
          );

        }
      )
      .filter(Boolean);
  }


  /* =======================================================
     ТЕМЫ МЕСЯЦА
     ======================================================= */

  function getMonthTopics(
    rawDescription
  ) {

    var source =
      removeLessonCount(
        rawDescription
      );


    source =
      removeNoLessons(
        source
      );


    var quoted =
      extractQuotedItems(
        source
      );


    if (
      quoted.length
    ) {
      return quoted;
    }


    var items =
      splitItems(
        source
      );


    return items.filter(
      function (item) {

        return (
          !/^недел[яи]\s*\d+$/i
            .test(item) &&
          item.length > 1
        );
      }
    );
  }


  /* =======================================================
     ТЕМЫ НЕДЕЛИ
     ======================================================= */

  function getWeekTags(
    rawDescription
  ) {

    var source =
      String(
        rawDescription ||
        ""
      );


    /*
     * Поддержка старого формата:
     *
     * дата || тема | тема | тема
     */
    if (
      source.indexOf(
        "||"
      ) !== -1
    ) {

      var doubleParts =
        source.split(
          "||"
        );


      /*
       * Если после первого ||
       * действительно есть темы.
       */
      var topics =
        doubleParts
          .slice(1)
          .join("||");


      var topicItems =
        splitItems(
          topics
        );


      if (
        topicItems.length
      ) {
        return topicItems;
      }
    }


    source =
      removeLessonCount(
        source
      );


    var quoted =
      extractQuotedItems(
        source
      );


    if (
      quoted.length
    ) {
      return quoted;
    }


    var items =
      splitItems(
        source
      );


    if (
      items.length
    ) {
      return items;
    }


    return source
      ? [source]
      : [];
  }


  /* =======================================================
     ДАТА НЕДЕЛИ
     ======================================================= */

  function getWeekTitle(
    title,
    description
  ) {

    var titleText =
      clean(title);


    var titleDate =
      titleText.match(
        DATE_RANGE_PATTERN
      );


    if (
      titleDate
    ) {
      return clean(
        titleDate[0]
      );
    }


    var descriptionDate =
      String(
        description || ""
      ).match(
        DATE_RANGE_PATTERN
      );


    if (
      descriptionDate
    ) {
      return clean(
        descriptionDate[0]
      );
    }


    return titleText;
  }


  /* =======================================================
     СОЗДАЁМ HTML ТЕГОВ
     ======================================================= */

  function createTagsHtml(
    items,
    wrapperClass,
    itemClass
  ) {

    if (
      !items ||
      !items.length
    ) {
      return "";
    }


    return (
      '<div class="' +
      wrapperClass +
      '">' +

      items
        .map(
          function (item) {

            return (
              '<span class="' +
              itemClass +
              '">' +
              escapeHtml(
                item
              ) +
              "</span>"
            );

          }
        )
        .join("") +

      "</div>"
    );
  }


  /* =======================================================
     ОПРЕДЕЛЯЕМ СТРАНИЦУ «АРХИВ»
     ======================================================= */

  function isArchiveRootPage(
    heading,
    rows
  ) {

    if (
      !/^архив$/i.test(
        clean(heading)
      )
    ) {
      return false;
    }


    var monthRows =
      rows.filter(
        function (row) {

          return MONTH_PATTERN.test(
            getRowTitle(row)
          );

        }
      );


    return (
      monthRows.length >= 1
    );
  }


  /* =======================================================
     ОПРЕДЕЛЯЕМ СТРАНИЦУ МЕСЯЦА
     ======================================================= */

  function isMonthPage(
    heading,
    rows
  ) {

    if (
      !MONTH_PATTERN.test(
        clean(heading)
      )
    ) {
      return false;
    }


    if (
      !rows.length
    ) {
      return false;
    }


    return rows.some(
      function (row) {

        var title =
          getRowTitle(row);


        var description =
          getRowDescriptionText(
            row
          );


        return (
          DATE_RANGE_PATTERN
            .test(title) ||

          WEEK_TITLE_PATTERN
            .test(title) ||

          DATE_RANGE_PATTERN
            .test(description) ||

          /недел[яи]\s*\d+/i
            .test(description)
        );
      }
    );
  }


  /* =======================================================
     ОПРЕДЕЛЯЕМ СТРАНИЦУ НЕДЕЛИ
     ======================================================= */

  function getLevelType(
    text
  ) {

    var value =
      clean(text);


    if (
      BASE_PATTERN.test(
        value
      )
    ) {
      return "base";
    }


    if (
      HARD_PATTERN.test(
        value
      )
    ) {
      return "hard";
    }


    return "";
  }


  function isWeekPage(
    heading,
    rows
  ) {

    if (
      !rows.length
    ) {
      return false;
    }


    var levelTypes =
      rows
        .map(
          function (row) {

            return getLevelType(
              getRowTitle(row)
            );

          }
        )
        .filter(Boolean);


    var hasBase =
      levelTypes.indexOf(
        "base"
      ) !== -1;


    var hasHard =
      levelTypes.indexOf(
        "hard"
      ) !== -1;


    /*
     * Самый надёжный признак:
     * внутри есть База + Хард.
     */
    if (
      hasBase &&
      hasHard
    ) {
      return true;
    }


    /*
     * Дополнительная защита.
     */
    var headingText =
      clean(heading);


    return (
      (
        WEEK_TITLE_PATTERN.test(
          headingText
        ) ||
        DATE_RANGE_PATTERN.test(
          headingText
        )
      ) &&
      (
        hasBase ||
        hasHard
      )
    );
  }


  /* =======================================================
     СПИСОК УРОКОВ
     ======================================================= */

  function findLessonList() {

    return (
      document.querySelector(
        ".lesson-list"
      ) ||

      document.querySelector(
        ".stream-table"
      ) ||

      document.querySelector(
        ".training-list"
      )
    );
  }
    
function findRouteLessonBlocks() {
  return Array.prototype.slice.call(
    document.querySelectorAll(
      ".enl-learning-route, .enl-hard-page"
    )
  );
}

function findRouteBlockLists(block) {

  if (!block) {
    return [];
  }

  var result = [];

  /*
   * Если сам блок является списком уроков,
   * используем его напрямую.
   */
  if (
    block.matches(
      ".lesson-list, .stream-table, .training-list"
    )
  ) {
    result.push(block);
  }

  /*
   * Если список находится внутри HTML-блока,
   * ищем его там.
   */
  Array.prototype.slice.call(
    block.querySelectorAll(
      ".lesson-list, .stream-table, .training-list"
    )
  ).forEach(
    function (list) {

      if (
        result.indexOf(list) === -1
      ) {
        result.push(list);
      }

    }
  );

  return result;
}
    
    
  function findLessonLinks(
    list
  ) {

    if (!list) {
      return [];
    }


    return Array.prototype.slice.call(
      list.querySelectorAll(
        "a[href]"
      )
    ).filter(
      function (link) {

        var source =
          clean(
            link.dataset
              .enlOriginalText ||

            link.innerText ||

            link.textContent ||

            ""
          );


        return (
          source.length > 3 &&
          LESSON_PATTERN.test(
            source
          )
        );
      }
    );
  }


  /* =======================================================
     ОПРЕДЕЛЯЕМ БАЗА / ХАРД
     ======================================================= */

function detectRouteType() {
  var routeBlocks =
    findRouteLessonBlocks();

  if (
    routeBlocks.some(
      function (block) {
        return block.classList.contains(
          "enl-learning-route"
        );
      }
    )
  ) {
    return "base";
  }

  if (
    routeBlocks.some(
      function (block) {
        return block.classList.contains(
          "enl-hard-page"
        );
      }
    )
  ) {
    return "hard";
  }

  if (
    document.body.classList.contains(
      "enl-learning-route"
    )
  ) {
    return "base";
  }

  if (
    document.body.classList.contains(
      "enl-hard-page"
    )
  ) {
    return "hard";
  }

  /*
   * Если специальных HTML-блоков нет,
   * оставляем старое определение
   * по самой странице.
   */

  if (
    document.body.classList.contains(
      "enl-learning-route"
    )
  ) {

    return "base";

  }


  if (
    document.body.classList.contains(
      "enl-hard-page"
    )
  ) {

    return "hard";

  }


  var heading =
    getPageHeading();


  var source =
    getPageSource();


  var list =
    findLessonList();


  if (!list) {
    return "";
  }


  var links =
    findLessonLinks(
      list
    );


  if (!links.length) {
    return "";
  }


  if (
    BASE_PATTERN.test(
      heading
    )
  ) {

    return "base";

  }


  if (
    HARD_PATTERN.test(
      heading
    )
  ) {

    return "hard";

  }


  if (
    BASE_PATTERN.test(
      source
    )
  ) {

    return "base";

  }


  if (
    HARD_PATTERN.test(
      source
    )
  ) {

    return "hard";

  }


  return "";
}

  /* =======================================================
     1. ОФОРМЛЯЕМ ГЛАВНЫЙ АРХИВ
     ======================================================= */

  function decorateArchiveRoot(
    table,
    rows
  ) {

    document.body.classList.add(
      "enl-archive-root"
    );


    var tbody =
      table.querySelector(
        "tbody"
      );


    if (!tbody) {
      return;
    }


    tbody.classList.add(
      "enl-archive-grid"
    );


    rows.forEach(
      function (row) {

        var titleText =
          getRowTitle(row);


        if (
          !MONTH_PATTERN.test(
            titleText
          )
        ) {
          return;
        }


        if (
          row.dataset
            .enlArchiveRootReady ===
          "1"
        ) {
          return;
        }


        var link =
          getRowLink(row);


        if (!link) {
          return;
        }


        var description =
          getRowDescriptionText(
            row
          );


        var topics =
          getMonthTopics(
            description
          );


        row.classList.add(
          "enl-archive-month-row"
        );


        link.classList.add(
          "enl-archive-month-link"
        );


        /*
         * Перерисовываем только
         * внутренность ссылки.
         *
         * href и системные классы
         * GetCourse сохраняются.
         */
        link.innerHTML =
          '<span class="enl-archive-month-title">' +
            escapeHtml(
              titleText.toLowerCase()
            ) +
          "</span>" +

          createTagsHtml(
            topics,
            "enl-archive-month-tags",
            "enl-archive-month-tag"
          );


        row.dataset
          .enlArchiveRootReady =
          "1";
      }
    );
  }


  /* =======================================================
     2. ОФОРМЛЯЕМ СТРАНИЦУ МЕСЯЦА
     ======================================================= */

  function decorateMonthPage(
    table,
    rows
  ) {

    document.body.classList.add(
      "enl-month-archive"
    );


    var tbody =
      table.querySelector(
        "tbody"
      );


    if (!tbody) {
      return;
    }


    tbody.classList.add(
      "enl-month-grid"
    );


    rows.forEach(
      function (row) {

        if (
          row.dataset
            .enlMonthReady ===
          "1"
        ) {
          return;
        }


        var originalTitle =
          getRowTitle(row);


        var description =
          getRowDescriptionText(
            row
          );


        /*
         * Не превращаем случайный
         * подтренинг в неделю.
         */
        var looksLikeWeek =
          (
            DATE_RANGE_PATTERN
              .test(originalTitle) ||

            WEEK_TITLE_PATTERN
              .test(originalTitle) ||

            DATE_RANGE_PATTERN
              .test(description) ||

            /недел[яи]\s*\d+/i
              .test(description)
          );


        if (
          !looksLikeWeek
        ) {
          return;
        }


        var link =
          getRowLink(row);


        if (!link) {
          return;
        }


        var weekTitle =
          getWeekTitle(
            originalTitle,
            description
          );


        var tags =
          getWeekTags(
            description
          );


        /*
         * Если описание содержит дату
         * в первой части через ||,
         * она не должна стать тегом.
         */
        tags =
          tags.filter(
            function (tag) {

              return !DATE_RANGE_PATTERN
                .test(tag);

            }
          );


        row.classList.add(
          "enl-month-week-row"
        );


        link.classList.add(
          "enl-month-week-link"
        );


        link.innerHTML =
          '<span class="enl-month-week-title">' +
            escapeHtml(
              weekTitle
            ) +
          "</span>" +

          createTagsHtml(
            tags,
            "enl-month-week-tags",
            "enl-month-week-tag"
          );


        row.dataset
          .enlMonthReady =
          "1";
      }
    );
  }


  /* =======================================================
     3. ДАННЫЕ КАРТОЧКИ УРОВНЯ
     ======================================================= */

  function getLevelDescription(
    row,
    level
  ) {

    var description =
      removeLessonCount(
        getRowDescriptionText(
          row
        )
      );


    description =
      removeNoLessons(
        description
      );


    /*
     * Убираем служебные маркеры,
     * если они случайно попали
     * в описание.
     */
    description =
      clean(
        description
          .replace(
            /^(база|базовый уровень|хард|hard|хард уровень)\s*[|—–\-:]?\s*/i,
            ""
          )
      );


    if (
      description
    ) {
      return description;
    }


    if (
      level === "base"
    ) {

      return (
        "основная программа недели"
      );
    }


    return (
      "дополнительные материалы недели"
    );
  }


  /* =======================================================
     4. ОФОРМЛЯЕМ СТРАНИЦУ НЕДЕЛИ
     ======================================================= */

  function decorateWeekPage(
    table,
    rows
  ) {

    document.body.classList.add(
      "enl-week-archive"
    );


    var tbody =
      table.querySelector(
        "tbody"
      );


    if (!tbody) {
      return;
    }


    tbody.classList.add(
      "enl-week-level-grid"
    );


    rows.forEach(
      function (row) {

        if (
          row.dataset
            .enlWeekLevelReady ===
          "1"
        ) {
          return;
        }


        var originalTitle =
          getRowTitle(row);


        var level =
          getLevelType(
            originalTitle
          );


        if (
          !level
        ) {
          return;
        }


        var link =
          getRowLink(row);


        if (!link) {
          return;
        }


        var description =
          getLevelDescription(
            row,
            level
          );


        var visibleTitle =
  level === "base"
    ? "обязательный план"
    : "допы на 100 баллов";


        row.classList.add(
          "enl-week-level-row"
        );


        link.classList.add(
          "enl-level-card"
        );


        link.dataset.enlLevel =
          level;


        link.innerHTML =
          '<span class="enl-level-title">' +
            escapeHtml(
              visibleTitle
            ) +
          "</span>" +

          '<span class="enl-level-description">' +
            escapeHtml(
              description
            ) +
          "</span>" +

          '<span class="enl-level-go">' +
            "<span>перейти</span>" +
            '<span class="enl-level-arrow">⟶</span>' +
          "</span>";


        row.dataset
          .enlWeekLevelReady =
          "1";
      }
    );
  }


  /* =======================================================
     ТИП УРОКА
     ======================================================= */

  function getLessonType(
    text
  ) {

    var source =
      clean(
        text
      ).toLowerCase();


    if (
      /данетк/.test(
        source
      )
    ) {

      return {
        key: "danetka",
        label: "данетка"
      };
    }


    if (
      /вебинар|созвон|практик/.test(
        source
      )
    ) {

      return {
        key: "webinar",
        label:
          "вебинар"
      };
    }


    if (
      /тест/.test(
        source
      )
    ) {

      return {
        key: "test",
        label: "тест"
      };
    }


    if (
      /видеоурок|видео-урок|видео урок|разбор|посмотрите.*урок/.test(
        source
      )
    ) {

      return {
        key: "video",
        label: "видеоурок"
      };
    }

        if (
      /домашн|пробн/.test(
        source
      )
    ) {

      return {
        key: "homework",
        label:
          "домашнее задание"
      };
    }

    return {
      key: "material",
      label: "урок"
    };
  }


  /* =======================================================
     СТРОКИ УРОКА
     ======================================================= */

  function getLessonLines(
    link
  ) {

    var original =
      getOriginalLinkText(
        link
      );


    return String(
      original || ""
    )
      .replace(
        /\u00A0/g,
        " "
      )
      .split(
        /\n+/
      )
      .map(
        function (line) {

          return clean(
            line
          );

        }
      )
      .filter(Boolean)
      .filter(
        function (
          line,
          index,
          array
        ) {

          return (
            array.indexOf(
              line
            ) === index
          );

        }
      );
  }

/* =======================================================
   ДЕДЛАЙН ИЗ ОПИСАНИЯ УРОКА
   Формат:

   due=24.08 в 17:00;

   В плашку выводится:

   24.08 в 17:00
   ======================================================= */

function getDeadlineLabel(
  row,
  link
) {

  var source = "";


  /* Текст всей строки урока */

  if (row) {

    source +=
      " " +
      (
        row.innerText ||
        row.textContent ||
        ""
      );

  }


  /* Текст ссылки */

  if (link) {

    source +=
      " " +
      (
        link.innerText ||
        link.textContent ||
        ""
      );

  }


  source =
    String(source || "")
      .replace(
        /\u00A0/g,
        " "
      );


  /*
   * Ищем:
   *
   * due=24.08 в 17:00;
   *
   * Всё после due= до ; берём
   * как текст дедлайна.
   */

  var match =
    source.match(
      /\bdue\s*=\s*([^;\n]+)/i
    );


  if (
    match &&
    clean(match[1])
  ) {

    return clean(
      match[1]
    );

  }


  return "";
}
    /* =======================================================
     ВЫБИРАЕМ ЗАГОЛОВОК УРОКА
     ======================================================= */

function findLessonTitle(
  lines
) {

  var candidates =
    lines
      .map(
        function (line) {

          /*
           * Отрезаем служебную часть:
           * название || дедлайн
           */

          return clean(
            String(line)
              .split("||")[0]
          );
        }
      )
      .filter(
        function (line) {

          if (!line) {
            return false;
          }


          if (
            /^(?:дедлайн|deadline)\s*[:—–\-]/i.test(
              line
            )
          ) {
            return false;
          }


          if (
            STATUS_PATTERN.test(
              line
            )
          ) {
            return false;
          }


          if (
            META_PATTERN.test(
              line
            ) &&
            !LESSON_PATTERN.test(
              line
            )
          ) {
            return false;
          }


          if (
            /^дедлайн$/i.test(
              line
            )
          ) {
            return false;
          }


          return (
            line.length > 2
          );
        }
      );


  var actionTitle =
    candidates.find(
      function (line) {

        return LESSON_PATTERN
          .test(line);
      }
    );


  return (
    actionTitle ||
    candidates[0] ||
    "материал курса"
  );
}

  /* =======================================================
     ОЧИЩАЕМ НАЗВАНИЕ УРОКА
     ======================================================= */

  function cleanLessonTitle(
    title,
    type
  ) {

    var result =
      clean(
        title
      );


    if (
      type === "video"
    ) {

      result =
        result
          .replace(
            /^посмотрите\s+/i,
            ""
          )
          .replace(
            /^(?:видеоурок|видео-урок|видео урок)(?:\s+по\s+теме)?\s*/i,
            ""
          )
          .replace(
            /^разбор\s+/i,
            ""
          );
    }


    if (
      type === "test" ||
      type === "danetka"
    ) {

      result =
        result.replace(
          /^решите\s+/i,
          ""
        );
    }
        


    if (
      type === "homework"
    ) {

      result =
        result
          .replace(
            /^выполните\s+/i,
            ""
          )
          .replace(
            /\bдомашнее задание\b/gi,
            "домашнее задание"
          );
    }


    if (
      type === "webinar"
    ) {

      result =
        result.replace(
          /^(?:посетите|посмотрите)\s+/i,
          ""
        );
    }

        if (
      type === "probnik"
    ) {

      result =
        result.replace(
          /^выполните\s+/i,
          ""
        );
    }

    if (
      type === "material"
    ) {

      result =
        result.replace(
          /^(?:прочитайте|изучите|посмотрите|откройте)\s+/i,
          ""
        );
    }


        result =
      result
        .replace(
          /^«([^«»]*)»$/,
          "$1"
        )
        .trim();


    if (
      !result
    ) {

      var fallbacks = {
        video:
          "видеоурок",

        test:
          "тест",

        danetka:
          "данетка",

        homework:
          "домашнее задание",

        webinar:
          "вебинар",

        material:
          "урок"
      };


      return (
        fallbacks[type] ||
        "материал курса"
      );
    }


    return (
      result
        .charAt(0)
        .toLowerCase() +
      result.slice(1)
    );
  }


  /* =======================================================
     СОСТОЯНИЕ УРОКА
     ======================================================= */

  function getLessonState(
  row,
  link,
  rawText
) {

  var nativeState =
    row
      ? row.querySelector(
          ".state-icon-block," +
          ".lesson-state," +
          ".user-state," +
          "[data-state]," +
          "[class*='accompl']," +
          "[class*='complete']," +
          "[class*='passed']"
        )
      : null;


  var source =
    [
      row
        ? row.className
        : "",

      link
        ? link.className
        : "",

      row
        ? row.getAttribute("data-state")
        : "",

      link
        ? link.getAttribute("data-state")
        : "",

      nativeState
        ? nativeState.className
        : "",

      nativeState
        ? nativeState.getAttribute("title")
        : "",

      nativeState
        ? nativeState.textContent
        : "",

      rawText
    ]
      .join(" ")
      .toLowerCase();


  /* Просрочено */

  if (
    /просроч|срок прош[её]л/.test(
      source
    )
  ) {
    return "overdue";
  }


  /* Дата ещё не наступила */

if (
    /user-state-not_reached|not_reached|noaccess|locked|not-available|недоступно|откроется|доступно с/.test(
      source
    )
) {
    return "not_reached";
}


  /*
   * Явно ещё не выполнено.
   * Проверяем ДО completed,
   * потому что фраза
   * «не выполнено» тоже содержит
   * слово «выполнено».
   */

  if (
    /не выполнено|не пройдено|есть задание|необходимо выполнить/.test(
      source
    )
  ) {
    return "available";
  }


  /* Родная иконка успешного выполнения */

  if (
    row &&
    row.querySelector(
      ".glyphicon-ok," +
      ".fa-check," +
      ".fa-check-circle"
    )
  ) {
    return "complete";
  }


  /* Выполнено */

  if (
    /задание выполнено|урок выполнен|урок пройден|выполнено|пройдено|accomplished|completed|complete|passed|success|done/.test(
      source
    )
  ) {
    return "complete";
  }


  return "available";
}

  /* =======================================================
     ПОДГОТОВКА ЗАГОЛОВКА БАЗЫ / ХАРДА
     ======================================================= */

  function decorateRouteHeading(
    routeType
  ) {

    var heading =
      getPageHeadingElement();


    if (!heading) {
      return;
    }


    var expected =
      routeType === "base"
        ? "base"
        : "hard";


    if (
      heading.dataset
        .enlRouteHeading ===
      expected
    ) {
      return;
    }


    /*
     * Сохраняем исходное название.
     */
    if (
      !heading.dataset
        .enlOriginalHeading
    ) {

      heading.dataset
        .enlOriginalHeading =
        clean(
          heading.textContent
        );
    }


    heading.classList.add(
      "enl-route-title"
    );


    var accent =
  routeType === "base"
    ? "обязательный"
    : "допы";


    heading.innerHTML =
      '<span class="enl-route-accent">' +
        accent +
      "</span>" +

      "<span>уровень</span>" +

      '<span class="enl-route-title-note">' +
        "" +
      "</span>";


    heading.dataset
      .enlRouteHeading =
      expected;
  }


  /* =======================================================
     СКРЫВАЕМ «НЕТ ТЕГОВ»
     ======================================================= */

  function hideNoTags() {

    Array.prototype.slice.call(
      document.querySelectorAll(
        "body *"
      )
    ).forEach(
      function (element) {

        if (
          element.children.length
        ) {
          return;
        }


        var text =
          clean(
            element.textContent
          ).toLowerCase();


        if (
          text === "нет тегов"
        ) {

          element.style
            .display =
            "none";
        }
      }
    );
  }


  /* =======================================================
     ОФОРМЛЯЕМ БАЗУ / ХАРД
     ======================================================= */

function decorateRoutePage(
  routeType
) {

  if (
    routeType === "base"
  ) {

    document.body.classList.add(
      "enl-learning-route"
    );

    document.body.dataset.enlAutoRoute =
      "base";

  } else {

    document.body.classList.add(
      "enl-hard-page"
    );

    document.body.dataset.enlAutoRoute =
      "hard";
  }


  decorateRouteHeading(
    routeType
  );


  hideNoTags();    

  var routeBlocks =
    findRouteLessonBlocks();
      

var lists = [];

routeBlocks.forEach(
  function (block) {

    var blockType =
      block.classList.contains(
        "enl-learning-route"
      )
        ? "base"
        : "hard";

    if (
      blockType !== routeType
    ) {
      return;
    }

    var blockLists =
      findRouteBlockLists(
        block
      );

    blockLists.forEach(
      function (list) {

        if (
          lists.indexOf(
            list
          ) === -1
        ) {
          lists.push(list);
        }

      }
    );

  }
);

if (!lists.length) {

  var defaultList =
    findLessonList();

  if (defaultList) {
    lists.push(defaultList);
  }
}

if (!lists.length) {
  return;
}

lists.forEach(
  function (list) {

    list.classList.add(
      "enl-lessons-list"
    );


    if (
      list.parentElement
    ) {

      list.parentElement
        .classList.add(
          "enl-lessons-shell"
        );
    }


    var grid =
      list.tagName === "TABLE"
        ? (
            list.querySelector(
              "tbody"
            ) ||
            list
          )
        : list;


    grid.classList.add(
      "enl-lessons-grid"
    );


    var links;

if (
  list.closest(
    ".enl-learning-route, .enl-hard-page"
  )
) {

  links =
Array.prototype.slice.call(
  list.querySelectorAll(
    "a[href], li.user-state-not_reached"
  )
).map(
  function(item){

    if (
      item.tagName.toLowerCase() === "li"
    ) {

      var fakeLink =
        item.querySelector("a");

      if (
        fakeLink
      ) {
        return fakeLink;
      }


      var div =
        document.createElement("a");

      div.href = "#";

      item.appendChild(div);

      return div;
    }


    return item;

  }
).filter(
  function(link){

    return true;

  }
);

} else {

  links =
    findLessonLinks(
      list
    );

}


    links.forEach(
      function (link) {

        /*
         * ЗДЕСЬ ОСТАЁТСЯ ВЕСЬ ТВОЙ
         * СУЩЕСТВУЮЩИЙ КОД ОБРАБОТКИ
         * ОДНОГО УРОКА.
         *
         * Начиная с:
         *
         * getOriginalLinkText(link);
         *
         * и до:
         *
         * link.dataset.enlArchiveLessonReady = "1";
         */

        getOriginalLinkText(
          link
        );


        var row =
          link.closest(
            "li, tr, .lesson-item, .lesson-list-item"
          ) ||
          link.parentElement;


        if (!row) {
          return;
        }


        var lines =
          getLessonLines(
            link
          );


        var deadlineLabel =
  getDeadlineLabel(
    row,
    link
  );


        var rawText =
          lines.join(" ");


        var state =
          getLessonState(
            row,
            link,
            rawText
          );

if (
  row.classList.contains(
    "user-state-not_reached"
  )
) {
  state = "not_reached";
}
          
        if (
          link.dataset
            .enlArchiveLessonReady ===
          "1"
        ) {

          link.dataset.enlState =
            state;

          return;
        }


        var rawTitle =
          findLessonTitle(
            lines
          );


        var type =
          getLessonType(
            rawTitle +
            " " +
            rawText
          );


        var title =
          cleanLessonTitle(
            rawTitle,
            type.key
          );


        row.classList.add(
          "enl-lesson-row"
        );


        link.classList.add(
          "enl-lesson-card"
        );

if (
  deadlineLabel
) {
  link.classList.add(
    "has-deadline"
  );
} else {
  link.classList.remove(
    "has-deadline"
  );
}
          
        link.dataset.enlType =
          type.key;


        link.dataset.enlState =
          state;


        link.innerHTML =
          '<span class="enl-card-content">' +

            '<span class="enl-card-top">' +

             '<span class="enl-step-label">' +
  escapeHtml(
    deadlineLabel
  ) +
"</span>" +

              '<span class="enl-type-label">' +
                escapeHtml(
                  type.label
                ) +
              "</span>" +

            "</span>" +

            '<span class="enl-card-title">' +
              escapeHtml(
                title
              ) +
            "</span>" +

          "</span>" +

          '<span class="enl-card-side">' +

            '<span class="enl-card-arrow" aria-hidden="true">' +
              "→" +
            "</span>" +

          "</span>";


        link.dataset
          .enlArchiveLessonReady =
          "1";

      }
    );

  }
);
        
}

  /* =======================================================
     ОПРЕДЕЛЯЕМ И ОФОРМЛЯЕМ ТЕКУЩУЮ СТРАНИЦУ
     ======================================================= */

  function apply() {

    if (
      isApplying ||
      !document.body
    ) {
      return;
    }


    isApplying = true;


    try {

      var heading =
        getPageHeading();


      var table =
        getStreamTable();


      var rows =
        getTrainingRows(
          table
        );


      /*
       * Сбрасываем классы,
       * чтобы при внутреннем переходе
       * не оставался предыдущий тип страницы.
       */
      removeBodyClasses();

/*
 * СПЕЦИАЛЬНЫЕ СПИСКИ БАЗЫ / ХАРДА
 *
 * Если на странице есть HTML-блок
 * .enl-learning-route или .enl-hard-page,
 * оформляем его в первую очередь.
 *
 * Это важно, потому что такой блок
 * может находиться внутри другого тренинга.
 */
var specialRouteType = detectRouteType();

var hasSpecialRouteBlock =
  document.querySelector(
    ".xdget-lessonList.enl-learning-route, " +
    ".xdget-lessonList.enl-hard-page"
  );

if (
  hasSpecialRouteBlock &&
  specialRouteType
) {

  decorateRoutePage(
    specialRouteType
  );

  return;
}
        /*
       * 1. Главный Архив.
       */
      if (
        table &&
        isArchiveRootPage(
          heading,
          rows
        )
      ) {

        decorateArchiveRoot(
          table,
          rows
        );

        return;
      }


      /*
       * 2. Месяц.
       */
      if (
        table &&
        isMonthPage(
          heading,
          rows
        )
      ) {

        decorateMonthPage(
          table,
          rows
        );

        return;
      }


      /*
       * 3. Неделя.
       *
       * Проверяем раньше базы/харда,
       * потому что на этой странице
       * одновременно присутствуют
       * слова «база» и «хард».
       */
      if (
  table &&
  isWeekPage(
    heading,
    rows
  )
) {

  decorateWeekPage(
    table,
    rows
  );

  return;
}


      /*
       * 4. Базовый / Хард.
       */
      var routeType =
        detectRouteType();


      if (
        routeType
      ) {

        decorateRoutePage(
          routeType
        );
      }

    } finally {

      isApplying = false;
    }
  }


  /* =======================================================
     ОТЛОЖЕННЫЙ ЗАПУСК
     ======================================================= */

  function scheduleApply() {

    window.clearTimeout(
      applyTimer
    );


    applyTimer =
      window.setTimeout(
        apply,
        90
      );
  }


  /* =======================================================
     ОТСЛЕЖИВАЕМ ВНУТРЕННИЕ ПЕРЕХОДЫ GETCOURSE
     ======================================================= */

  function watchHistory() {

    if (
      window.__ENL_ARCHIVE_HISTORY__
    ) {
      return;
    }


    window.__ENL_ARCHIVE_HISTORY__ =
      true;


    var nativePushState =
      history.pushState;


    var nativeReplaceState =
      history.replaceState;


    history.pushState =
      function () {

        var result =
          nativePushState.apply(
            history,
            arguments
          );


        window.setTimeout(
          scheduleApply,
          0
        );


        return result;
      };


    history.replaceState =
      function () {

        var result =
          nativeReplaceState.apply(
            history,
            arguments
          );


        window.setTimeout(
          scheduleApply,
          0
        );


        return result;
      };


    window.addEventListener(
      "popstate",
      scheduleApply
    );
  }


  /* =======================================================
     OBSERVER GETCOURSE
     ======================================================= */

  function startObserver() {

    if (
      !window.MutationObserver ||
      observer
    ) {
      return;
    }


    observer =
      new MutationObserver(
        function () {

          scheduleApply();

        }
      );


    observer.observe(
      document.body,
      {
        childList:
          true,

        subtree:
          true
      }
    );


    /*
     * Не держим наблюдатель
     * постоянно на тяжёлой странице.
     *
     * Пяти секунд обычно достаточно,
     * чтобы GetCourse дорисовал таблицы.
     *
     * Внутренние переходы отдельно
     * ловятся через history.
     */
    stopObserverTimer =
      window.setTimeout(
        function () {

          if (
            observer
          ) {

            observer.disconnect();

            observer = null;
          }

        },
        5000
      );
  }


  /* =======================================================
     ЗАПУСК
     ======================================================= */

  function start() {

    watchHistory();


    apply();


    /*
     * Контрольные попытки нужны,
     * потому что GetCourse иногда
     * выводит таблицу позже DOMContentLoaded.
     */

    window.setTimeout(
      apply,
      350
    );


    window.setTimeout(
      apply,
      900
    );


    window.setTimeout(
      apply,
      1800
    );


    startObserver();
  }


  if (
    document.readyState ===
    "loading"
  ) {

    document.addEventListener(
      "DOMContentLoaded",
      start,
      {
        once:
          true
      }
    );

  } else {

    start();
  }

})();

